﻿#include "UdpCodec.h"

#include "UdpIOer.h"
#include "DataPackage_UdpCodec.h"
#include "RegisterCenter_Device.h"
#include "DeviceRegisterCodec.h"
#include "Device.h"
#include "UdpController.h"

#include <qhostaddress.h>
#include <qdatetime.h>

#include "UdpCodec_HeartBeat.h"
#include "UdpCodec_SensorData.h"
#include "UdpCodec_TurnTable.h"
#include "UdpCodec_MCUCtrl.h"
#include "UdpCodec_Register.h"
#include "UdpCodec_Test.h"

UdpCodec::UdpCodec()
{
  setObjectName(getClassNameFirstLow<UdpCodec>());
  codecMap.insert(HeartBeat,new UdpCodec_HeartBeat());
  codecMap.insert(SensorData,new UdpCodec_SensorData());
  codecMap.insert(TurnTable,new UdpCodec_TurnTable());
  codecMap.insert(MCUCtrl,new UdpCodec_MCUCtrl());
  codecMap.insert(Register,new UdpCodec_Register());
  codecMap.insert(Test,new UdpCodec_Test());
}

UdpCodec::~UdpCodec()
{
  for(unsigned char key:codecMap.keys())
    {
      delete codecMap.take(key);
    }
}

void UdpCodec::code(DataPackage_UdpCodec *dataPackageInfo)
{
  if(Q_NULLPTR==dataPackageInfo)//空指针直接返回
    {
      return ;
    }
  QNetworkDatagram* qNetworkDatagram=dataPackageInfo->toNetworkDatagram();
  udpIOer->sendData(*qNetworkDatagram);
  delete qNetworkDatagram;
}

bool UdpCodec::code(uint deviceId, ushort msgId, uchar type, QByteArray data, bool emergency)
{
  Device* device=registerCenter_Device->getDeviceById(deviceId);
  if(!device)
    {
      logSaver->saveLog(QString("UdpCodec,device %1 is offline,can not send data to it").arg(deviceId));
      return false;
    }

  DataPackage_UdpCodec* dataPackage_UdpCodec=new DataPackage_UdpCodec();
  dataPackage_UdpCodec
      ->setReceiverAddress(device->getHostAddress())
      ->setReceiverPort(device->getPort())
      ->setDeviceId(deviceId)
      ->setMsgId(msgId)
      ->setPackageType(type)
      ->setData(data);
  if(udpController)
    {
      //启动UDP控制，则采用控制器发送
      udpController->send(dataPackage_UdpCodec,emergency);
    }
  else
    {
      //关闭UDP控制，直接发送
      dataPackage_UdpCodec->setTimeStamp(QDateTime::currentMSecsSinceEpoch());
      code(dataPackage_UdpCodec);
      dataPackage_UdpCodec->deleteLater();
    }
  return true;
}

DataPackage_UdpCodec* UdpCodec::decode(DataPackage_UdpCodec* dataPackageInfo_Device)
{
  uchar packageType=dataPackageInfo_Device->getPackageType();
  if(DataPackgeType::Size<=packageType)
    {
      logSaver->saveLog("UdpCodec,uncorrect dataPackageType,data rejected");//不正确的数据包类型，丢弃
      return Q_NULLPTR;
    }
  int deviceId=dataPackageInfo_Device->getDeviceId();
  if(DataPackgeType::Register==packageType)//如果是注册包
    {
      return codecMap.value(DataPackgeType::Register)->decode(dataPackageInfo_Device);
    }
  if(!registerCenter_Device->isOnline(deviceId))//判断设备是否注册
    {
      logSaver->saveLog("UdpCodec,device "+QString::number(deviceId)+" is unregistered");
      return DeviceRegisterCodec::makeAck(dataPackageInfo_Device,DeviceRegisterCodec::Reset)
          ->setPackageType(DataPackgeType::Register);//若未注册则返回重置连接
    }
  //控制器
  if(udpController)
    {
      if(udpController->receive(dataPackageInfo_Device))
        {
          return codecMap.value(packageType)->decode(dataPackageInfo_Device);
        }
      else
        {
          return Q_NULLPTR;
        }
    }
  else
    {
      return codecMap.value(packageType)->decode(dataPackageInfo_Device);
    }
}

void UdpCodec::slot_decode(QNetworkDatagram qNetworkDatagram)
{
  DataPackage_UdpCodec* dataPackageInfo_Device=DataPackage_UdpCodec::fromNetworkDatagram(&qNetworkDatagram);//尝试解析数据包
  if(Q_NULLPTR==dataPackageInfo_Device)
    {
      logSaver->saveLog("UdpCodec,uncorrect dataPackage,decode data faild");//解析失败则丢弃
      return;
    }
  logSaver->saveLog("UdpCodec,packageType:"+QString::number(dataPackageInfo_Device->getPackageType(),16));
  logSaver->saveLog("UdpCodec,msgId:"+QString::number(dataPackageInfo_Device->getMsgId()));
  //  logSaver->saveLog("UdpCodec,deviceId"+QString::number(dataPackageInfo_Device->getDeviceId()));
  //  logSaver->saveLog("UdpCodec,data:"+dataPackageInfo_Device->getData().toHex(),LogSaver::Debug);
  code(decode(dataPackageInfo_Device));
  dataPackageInfo_Device->deleteLater();
}

int UdpCodec::getUdpHeadSize()
{
  return udpHeadSize;
}

UdpIOer* UdpCodec::getUdpIOer()
{
  return udpIOer;
}

UdpCodec *UdpCodec::setUdpIOer(UdpIOer* udpIOer)
{
  if(Q_NULLPTR!=this->udpIOer)
    {
      disconnect(this->udpIOer,&UdpIOer::signal_newMessage,this,&UdpCodec::slot_decode);
    }
  if(Q_NULLPTR!=(this->udpIOer=udpIOer))
    {
      connect(this->udpIOer,&UdpIOer::signal_newMessage,this,&UdpCodec::slot_decode,Qt::QueuedConnection);
    }
  printInjection(this,udpIOer);
  return this;
}

RegisterCenter_Device* UdpCodec::getRegisterCenter_Device()const
{
  return registerCenter_Device;
}

UdpCodec* UdpCodec::setRegisterCenter_Device(RegisterCenter_Device* const registerCenter_Device)
{
  this->registerCenter_Device=registerCenter_Device;
  printInjection(this,registerCenter_Device);
  return this;
}

UdpController* UdpCodec::getUdpController()const
{
  return udpController;
}

UdpCodec* UdpCodec::setUdpController(UdpController*const udpController)
{
  this->udpController=udpController;
  printInjection(this,udpController);
  return this;
}

void UdpCodec::objectAutoInjection(QHash<QString,QObject*>* objMap)
{
  setUdpIOer(getObjFromMap<UdpIOer>(objMap));
  setRegisterCenter_Device(getObjFromMap<RegisterCenter_Device>(objMap));
  setUdpController(getObjFromMap<UdpController>(objMap));
  for(unsigned char key:codecMap.keys())
    {
      ObjAutoInject* temp=dynamic_cast<ObjAutoInject*>(codecMap.value(key));
      if(temp)
        {
          temp->objectAutoInjection(objMap);
        }
    }
}
